#define CPU_ONLY
#define AMBER_USE_CAFFE_BLOB

#include "base64.h"
#include "image.hpp"
#include "md5.h"
#include <caffe/caffe.hpp>
#include <caffe/data_transformer.hpp>
#include <caffe/util/io.hpp>
#include <cmath>
#include <hiredis/hiredis.h>
#include <iostream>
#include <json/json.h>
#include <memory>
#include <opencv2/opencv.hpp>
#include <string>
using namespace amber;

// 全局变量 _net
std::shared_ptr<caffe::Net<float>> _net;

void ImageToBase64(cv::Mat image, std::string& imageBase64)
{
    std::vector<uchar> imageBuffer;
    std::vector<int> parameters;
    parameters.push_back(CV_IMWRITE_JPEG_QUALITY);
    parameters.push_back(50);

    // 编码为JPEG
    cv::imencode(".jpg", image, imageBuffer, parameters);
    std::string imageData(reinterpret_cast<char*>(imageBuffer.data()), imageBuffer.size());

    // 转换为Base64
    Base64::Encode(imageData, &imageBase64);
}

int main()
{
    std::cout << "hello world!" << '\n';
    redisContext* reids = redisConnect("127.0.0.1", 6379);

    redisReply* _reply = (redisReply*)redisCommand(reids, "LINDEX picture 0");
    std::string job_json = _reply->str;
    freeReplyObject(_reply);

    // picture key
    Json::Value job;
    Json::Reader reader;
    reader.parse(job_json, job);

    std::string key = job["uuid"].asString();
    std::string picture_base64 = job["picture"].asString();
    std::cout << "key:" << key << std::endl;
    std::string picture_data = "";
    Base64::Decode(picture_base64, &picture_data);

    amber::Image original(picture_data);
    original.Show();

    std::vector<Image> list = original.Split(32, 32, true);
    // 读取网络定义
    caffe::NetParameter netParam;
    caffe::ReadNetParamsFromTextFileOrDie("models/net.prototxt", &netParam);
    netParam.mutable_state()->set_phase(caffe::TEST);

    // 使用网络定义参数创建网络
    _net.reset(new caffe::Net<float>(netParam));
    // 读取训练的权重参数
    _net->CopyTrainedLayersFromBinaryProto("models/weight.caffemodel");

    std::vector<Image> list_compressed;

    for (auto image : list) {
        // image.Show();
        // 输入数据向量
        std::vector<caffe::Blob<float>*> bottomVector;
        // 添加到数据向量中
        bottomVector.push_back(image.asBlob());
        // 执行网络前传，压缩
        _net->Forward(bottomVector);
        // 获取压缩结果
        const boost::shared_ptr<caffe::Blob<float>> encodedBlob = _net->blob_by_name("encode1neuron");

        list_compressed.push_back(amber::Image(encodedBlob.get(), 16, 16));
    }

    auto compressed = amber::Image(list_compressed, std::ceil(original.image.cols / 32) * 16, std::ceil(original.image.rows / 32) * 16);
    compressed.Show();

    // 将压缩后图像转换回Base64
    std::string compressedBase64;
    ImageToBase64(compressed.image, compressedBase64);

    const char* command = (std::string("SET ") + key + std::string(" ") + compressedBase64).c_str();
    _reply = (redisReply*)redisCommand(reids, command);

    return 0;
}
